package cn.turboinfo.dongying.api.provider.common.service.impl.file;

import cn.turboinfo.dongying.api.domain.common.service.file.FileAttachmentService;
import cn.turboinfo.dongying.api.domain.common.service.site.SiteUrlService;
import cn.turboinfo.dongying.api.entity.common.exception.file.FileAttachmentException;
import cn.turboinfo.dongying.api.entity.common.pojo.file.FileAttachment;
import cn.turboinfo.dongying.api.entity.common.pojo.file.FileAttachmentCreator;
import cn.turboinfo.dongying.api.entity.common.pojo.file.FileAttachmentUpdater;
import cn.turboinfo.dongying.api.provider.common.repository.database.file.FileAttachmentDAO;
import cn.turboinfo.dongying.api.provider.common.repository.database.file.FileAttachmentPO;
import lombok.RequiredArgsConstructor;
import net.sunshow.toolkit.core.qbean.api.request.QPage;
import net.sunshow.toolkit.core.qbean.api.request.QRequest;
import net.sunshow.toolkit.core.qbean.api.response.QResponse;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanCreatorHelper;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanUpdaterHelper;
import net.sunshow.toolkit.core.qbean.helper.service.impl.AbstractQServiceImpl;
import nxcloud.foundation.core.idgenerator.IdGeneratorFacade;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;

@RequiredArgsConstructor
@Service
public class FileAttachmentServiceImpl extends AbstractQServiceImpl<FileAttachment> implements FileAttachmentService {
    private final FileAttachmentDAO fileAttachmentDAO;

    /**
     * 附件上传目录
     */
    @Value("${kit.file.attachment.upload-path:}")
    private String uploadPath;

    private final SiteUrlService siteUrlService;

    private final IdGeneratorFacade<Long> idGeneratorFacade;

    @Override
    public Optional<FileAttachment> getById(Long id) {
        return fileAttachmentDAO.findById(id).map(this::convertQBean);
    }

    @Override
    public FileAttachment getByIdEnsure(Long id) {
        return getById(id).orElseThrow(this.getExceptionSupplier("未找到数据, id=" + id, null));
    }

    @Override
    public List<FileAttachment> findByIdCollection(Collection<Long> idCollection) {
        return convertStreamQBeanToList(fileAttachmentDAO.findByIdInOrderByIdDesc(idCollection).stream());
    }

    @Override
    @Transactional
    public FileAttachment save(FileAttachmentCreator creator) throws FileAttachmentException {
        FileAttachmentPO fileAttachmentPO = new FileAttachmentPO();

        QBeanCreatorHelper.copyCreatorField(fileAttachmentPO, creator);

        // 手动生成ID
        fileAttachmentPO.setId(idGeneratorFacade.nextId());
        return convertQBean(fileAttachmentDAO.save(fileAttachmentPO));
    }

    @Override
    @Transactional
    public FileAttachment update(FileAttachmentUpdater updater) throws FileAttachmentException {
        FileAttachmentPO fileAttachmentPO = getEntityWithNullCheckForUpdate(updater.getUpdateId(), fileAttachmentDAO);

        QBeanUpdaterHelper.copyUpdaterField(fileAttachmentPO, updater);

        return convertQBean(fileAttachmentPO);
    }

    @Override
    public QResponse<FileAttachment> findAll(QRequest request, QPage requestPage) {
        return convertQResponse(findAllInternal(request, requestPage));
    }

    @Override
    public List<FileAttachment> findByRefId(Long refId) {
        return convertStreamQBeanToList(fileAttachmentDAO.findByRefIdOrderById(refId).stream());
    }

    @Override
    public List<FileAttachment> findByRefAndRefType(Long refId, Collection<String> refTypeCollection) {
        return convertStreamQBeanToList(fileAttachmentDAO.findByRefIdAndRefTypeInOrderById(refId, refTypeCollection).stream());
    }

    @Override
    public List<FileAttachment> findByRefIdAndRefType(Long refId, String refType) {
        return convertStreamQBeanToList(fileAttachmentDAO.findByRefIdAndRefTypeOrderById(refId, refType).stream());
    }

    @Override
    public List<FileAttachment> findByRefIdInAndRefType(Collection<Long> refIdCollection, String refType) {
        return convertStreamQBeanToList(fileAttachmentDAO.findByRefIdInAndRefTypeOrderById(refIdCollection, refType).stream());
    }

    @Override
    public List<FileAttachment> findByRefIdCollection(Collection<Long> refIdCollection) {
        return convertStreamQBeanToList(fileAttachmentDAO.findByRefIdInOrderById(refIdCollection).stream());
    }

    private Page<FileAttachmentPO> findAllInternal(QRequest request, QPage requestPage) {
        return fileAttachmentDAO.findAll(convertSpecification(request), convertPageable(requestPage));
    }

    @Override
    @Transactional
    public void deleteById(Long id) throws FileAttachmentException {
        FileAttachmentPO fileAttachmentPO = getEntityWithNullCheckForUpdate(id, fileAttachmentDAO);
        fileAttachmentPO.setDeletedTime(System.currentTimeMillis());
    }

    @Override
    @Transactional
    public void deleteByIdCollection(Collection<Long> refIdCollection) throws FileAttachmentException {
        refIdCollection.forEach(id -> {
            FileAttachmentPO fileAttachmentPO = getEntityWithNullCheckForUpdate(id, fileAttachmentDAO);
            fileAttachmentPO.setDeletedTime(System.currentTimeMillis());
        });
    }

    @Override
    public Path resolveAbsolutePath(String relativePath) {
        Path outputDirectory = new File(uploadPath).toPath();
        if (!relativePath.isEmpty()) {
            for (String p : StringUtils.split(relativePath, "/")) {
                outputDirectory = outputDirectory.resolve(p);
            }
        }
        return outputDirectory;
    }

    @Override
    @Transactional
    public FileAttachment updateRefId(Long id, Long refId) throws FileAttachmentException {
        FileAttachmentPO fileAttachmentPO = getEntityWithNullCheckForUpdate(id, fileAttachmentDAO);
        fileAttachmentPO.setRefId(refId);
        return convertQBean(fileAttachmentPO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRefId(List<Long> ids, Long refId) throws FileAttachmentException {
        ids.forEach(id -> {
            try {
                FileAttachmentPO fileAttachmentPO = getEntityWithNullCheckForUpdate(id, fileAttachmentDAO);
                fileAttachmentPO.setRefId(refId);
            } catch (Exception e) {
            }
        });
    }

    @Override
    public FileAttachment assembleExternalUrl(FileAttachment fileAttachment) {
        fileAttachment.setExternalUrl(siteUrlService.getUploadExternalImgUrl(fileAttachment.getRelativePath() + "/" + fileAttachment.getFilename()));
        return fileAttachment;
    }

    @Override
    protected Supplier<? extends RuntimeException> getExceptionSupplier(String message,
                                                                        Throwable cause) {
        return () -> new FileAttachmentException(message, cause);
    }
}
